import { GameConfig } from '../configs/GameConfig';
import { Attribute } from '../etc/Attribute';
import { updater } from '../etc/Updater';
import { CDTimer } from '../gameEtc/CDTimer';
import Appearance from '../model/Appearance';
import { MainUI } from '../ui/MainUI';
import { GrowModuleData } from './GrowModule';
import { LevelModuleC } from './LevelModule';

export class PlayerModuleData extends Subdata {
    @Decorator.persistence()
    reserveAttribute: Attribute.AttributeArray;
    
    get dataName(): string { return 'PlayerModuleData' }
    
    protected initDefaultData() {
        this.reserveAttribute = {};
        this.reserveAttribute[Attribute.EnumAttributeType.money] = 0;
        this.save(true);
    }
}

export class PlayerModuleC extends ModuleC<PlayerModuleS, PlayerModuleData>{
    // 即时属性存根(用于记录属性变更)
    private playerStashedAttrBuffer = {};
    // 即时属性容器
    private attribute: Attribute.AttributeValueObject = new Attribute.AttributeValueObject();

    onAddForceClear: Action = new Action()

    private levelMD:LevelModuleC
    
    sprintCD:CDTimer = new CDTimer(2000)

    private defaultMoveSpeed = 450
    private defaultJumpHeight = 150

    protected onStart() {
        this.defaultMoveSpeed = this.localPlayer.character.maxWalkSpeed
        this.defaultJumpHeight = this.localPlayer.character.maxJumpHeight

        this.levelMD = ModuleService.getModule(LevelModuleC)

        this.levelMD.onPlayerDeadEvent.add(this.onPlayerDead, this)

        this.data.onDataChange.add(this.onPlayerAttributeDataChanged, this);
        this.syncPlayerStashedAttribute();

        UIService.show(MainUI)
    }

    protected onUpdate(): void { }

    private onPlayerDead() {
        this.onAddForceClear.call()
        // 清空左右冲量
        this.clearPlayerDirectionalImpulse()
    }

    @updater.updateByFrameInterval(3)
    private standChecker(){
        if(!this.localPlayer || !this.localPlayer.character || !this.localPlayer.character.isReady){
            return
        }
        if(!this.localPlayer.character.isJumping){
            this.lastStandPosition = this.localPlayer.character.worldTransform.position
        }
    }

    private lastStandPosition:Vector
    getPlayerLastStandPosition():Vector{
        return this.lastStandPosition
    }

    // 清除玩家左右前后冲量
    clearPlayerDirectionalImpulse(){
        let velocity = this.localPlayer.character.velocity
        this.localPlayer.character.addImpulse(new Vector(-velocity.x, -velocity.y, 0), true)
    }

    // 获取玩家属性
    getAttr(type: Attribute.EnumAttributeType): number {
        if (!Attribute.IsStashAttribute(type)) return this.attribute.getValue(type)
        return this.data.reserveAttribute[type] || 0;
    }
    
    // 比对变更属性
    private onPlayerAttributeDataChanged() {
        this.syncPlayerStashedAttribute();
    }

    requestAddMoney(count:number){
        this.server.net_add_money(count)
    }

    // 同步玩家数据到缓存数据
    private syncPlayerStashedAttribute() {
        Object.assign(this.playerStashedAttrBuffer, this.data.reserveAttribute);
    }

    // 服务器发送的请求玩家233名称
    net_get_nick_name() {
        let name = AccountService.getNickName()
        if(SystemUtil.isPIE){
            name = `本地玩家${this.localPlayerId}`
        }
        this.server.net_nick_name(name)
    }

    // 服务器发送的初始化属性列表
    net_init_attr(attributeArray: Attribute.AttributeArray) {
        for (let type in attributeArray) {
            let typeEnum = Number(type)
            let val = attributeArray[type];
            let typeKey = Number(type)
            this.attribute.setAttribute(typeKey, val);

            if(typeEnum == Attribute.EnumAttributeType.extraMoveSpeed){
                let walkSpeed = this.defaultMoveSpeed + val
                this.localPlayer.character.maxWalkSpeed = walkSpeed
            }

            if(typeEnum == Attribute.EnumAttributeType.extraJumpForce){
                let jumpHeight = this.defaultJumpHeight + val
                this.localPlayer.character.maxJumpHeight = jumpHeight
            }

            if(SystemUtil.isPIE){
                console.log(`属性变更:${typeKey}:${val}`);
            }
        }
    }

    // 服务器发送的属性变更
    net_change_attr(type: Attribute.EnumAttributeType, value: number) {
        this.attribute.setAttribute(type, value);
    }
}

export class PlayerModuleS extends ModuleS<PlayerModuleC, PlayerModuleData>{
    onPlayerNamePullSuccess:Action1<number> = new Action1()

    private appearanceMapping: Map<number, Appearance> = new Map()
    private playerAttributeMap: Map<number, Attribute.AttributeValueObject> = new Map();

    protected onPlayerEnterGame(player: mw.Player) {
        // 空名字
        player.character.asyncReady().then(character => { character.displayName = " " })
        // 初始化玩家信息脚本
        this.initPlayerAppearanceScript(player)
        // 初始化玩家属性
        this.initPlayerAttribute(player.playerId)
        // 计算属性
        this.recalculateAllAttribute(player)
    }

    protected onPlayerLeft(player: mw.Player): void {
        // 外观
        if (this.appearanceMapping.has(player.playerId)) {
            let appearance = this.appearanceMapping.get(player.playerId)
            appearance.destroy()
            this.appearanceMapping.delete(player.playerId)
        }
        // 属性
        this.playerAttributeMap.delete(player.playerId);
    }
    
    reducePlayerAttr(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        if (!Player.getPlayer(playerID)) return //已下线
        if (Attribute.IsStashAttribute(type)) {
            this.reducePlayerAttrStash(playerID, type, value);
            return
        }
        this.reducePlayerAttrIT(playerID, type, value);
    }

    addPlayerAttr(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        if (!Player.getPlayer(playerID)) return //已下线
        if (Attribute.IsStashAttribute(type)) {
            this.addPlayerAttrStash(playerID, type, value);
            return
        }
        this.addPlayerAttrIT(playerID, type, value);
    }
    
    getPlayerAttr(playerID: number, type: Attribute.EnumAttributeType): number {
        if (!Player.getPlayer(playerID)) return 0 //已下线
        // 是否为存储属性
        if (Attribute.IsStashAttribute(type)) {
            return this.getPlayerData(playerID).reserveAttribute[type] || 0;
        }
        return this.playerAttributeMap.get(playerID).getValue(type);
    }
    
    // 重新计算计算玩家所有属性并存储
    recalculateAllAttribute(player: Player) {
        let attrVo: Attribute.AttributeValueObject = new Attribute.AttributeValueObject();
        let playerID = player.playerId; 

        let growData = DataCenterS.getData(playerID, GrowModuleData)
        for (const key in growData.growMap) {
            let growCfgID = growData.growMap[key]
            let growCfg = GameConfig.Grow.getElement(growCfgID)
            attrVo.addValue(growCfg.AttributeType, growCfg.Value)
        }
        // 保存
        this.playerAttributeMap.set(playerID, attrVo);
        // 同步
        this.getClient(playerID).net_init_attr(attrVo.attributeArray);
    }

    // 减少玩家储存属性(不随游戏结束清空的属性)
    private reducePlayerAttrStash(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let data = this.getPlayerData(playerID);
        data.reserveAttribute[type] = data.reserveAttribute[type] - value;
        data.save(true);
    }

    // 增加玩家储存属性(不随游戏结束清空的属性)
    private addPlayerAttrStash(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let data = this.getPlayerData(playerID);
        data.reserveAttribute[type] += value;
        data.save(true);
    }

    // 减少玩家即时属性
    private reducePlayerAttrIT(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let vo = this.playerAttributeMap.get(playerID);
        vo.reduceValue(type, value);
        this.syncChangePlayerAttr(playerID, type);
    }

    // 增加玩家即时属性
    private addPlayerAttrIT(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let vo = this.playerAttributeMap.get(playerID);
        vo.addValue(type, value);
        this.syncChangePlayerAttr(playerID, type);
    }
    
    // 同步属性变更(单一)
    private syncChangePlayerAttr(playerID: number, type: Attribute.EnumAttributeType) {
        let attrVo = this.playerAttributeMap.get(playerID);
        this.getClient(playerID).net_change_attr(type, attrVo.getValue(type));
    }

    // 初始化玩家外观脚本
    private async initPlayerAppearanceScript(player: Player) {
        let playerID = player.playerId
        if (this.appearanceMapping.has(playerID)) return

        let appearance = await Script.spawnScript(Appearance)
        appearance.init(playerID)
        appearance.playerName = ' ' // 不加这个有问题

        this.appearanceMapping.set(playerID, appearance)

        this.getClient(player.playerId).net_get_nick_name()
    }

    // 初始化玩家属性
    private initPlayerAttribute(playerID:number){
        if(!this.playerAttributeMap.has(playerID)){
            let attrVo = new Attribute.AttributeValueObject()
            this.playerAttributeMap.set(playerID, attrVo)
        }
    }

    net_nick_name(name: string) {
        if(!this.appearanceMapping.has(this.currentPlayerId)) return
        this.appearanceMapping.get(this.currentPlayerId).playerName = name
        // 玩家初始化名称完成
        this.onPlayerNamePullSuccess.call(this.currentPlayerId)
    }

    net_add_money(count:number) {
        this.addPlayerAttr(this.currentPlayerId, Attribute.EnumAttributeType.money, count)
    }
}